using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
using Microsoft.Xna.Framework;
using System.Diagnostics;

namespace Dragoon
{


    public enum MenuItemType {Header,Option}

    public class MenuItem
    {
        public readonly int Index;
        private string _text;
        public readonly MenuItemType Type;
        private bool _isSelected;
        internal MenuItem(int index, string text)
        {
            Debug.Assert(index > -1);
            Index = index;
            Text = text;
            Type =  MenuItemType.Option;
            _isSelected = index == 0;
        }

        public string Text
        {
            get
            {
                return _text;
            }
            internal set
            {
                _text = value;
            }
        }

        internal MenuItem(string text)
        {
            Index = -1;
            Text = text;
            Type = MenuItemType.Option;
            _isSelected = false;
        }

        public bool IsSelected
        {
            get
            {
                return _isSelected;
            }
            internal set
            {
                Debug.Assert(Index != -1,"This item cannot be selected");
                _isSelected = value;
            }
        }
    }
    
    public class MenuEvent : EventArgs
    {
        public readonly MenuItem SelectedItem;
        public readonly GameTime Time;
        
        /// <summary>
        /// Did the user make a selection?
        /// </summary>
        public bool HasSelected
        {
            get { return SelectedItem != null ; }
        }

        internal MenuEvent(GameTime time, MenuItem item)
        {
            Time = time;
            SelectedItem = item;
        }
    }

    public class Menu 
    {
        private readonly List<MenuItem> _items;
        private MenuItem _selectedItem;

        internal Menu(string[] header, string[] options)
        {
            _items = new List<MenuItem>();
            foreach (string s in header)
                _items.Add(new MenuItem(s));
            int index = 0;
            foreach (string s in options)
            {
                MenuItem it = new MenuItem(index++, s);
                if (it.IsSelected)
                    _selectedItem = it;
                _items.Add(it);
            }
            Debug.Assert(_selectedItem != null, "not item is selected");
        }

        public IEnumerable<MenuItem> Items { get { return _items; } }

        internal MenuItem ItemAt(int index)
        {
            return _items[index];
        }

        public int Count { get { return _items.Count; } }
        
        public MenuItem SelectedItem
        {
            get
            {
                return _selectedItem;
            }

        }

        private MenuItem FindItemWithIndex(int index)
        {
            Predicate<MenuItem> findIndex = delegate(MenuItem i)
                { return i.Index == index; };
            return _items.Find(findIndex);
        }

        public void SelectNext()
        {
            SelectedItem.IsSelected = false;
            if (SelectedItem.Index == _items[_items.Count - 1].Index)
                _selectedItem = FindItemWithIndex(0);
            else
                _selectedItem  = FindItemWithIndex(SelectedItem.Index + 1);
            SelectedItem.IsSelected = true;
        }

        public void SelectPrevious()
        {
            SelectedItem.IsSelected = false;
            if (SelectedItem.Index == 0)
                _selectedItem = _items[_items.Count - 1];
            else
                _selectedItem = FindItemWithIndex(SelectedItem.Index - 1);
            Debug.Assert(SelectedItem != null);
            SelectedItem.IsSelected = true;
        }


        public event EventHandler<MenuEvent> OnClose;

        public void Close(GameTime time)
        {
            if (OnClose != null)
                OnClose(this, new MenuEvent(time,SelectedItem));
        }

        public void Cancel(GameTime time)
        {
            if (OnClose != null)
                OnClose(this, new MenuEvent(time,null));
        }
    }
}
